boolean first = false;
int x0, y0, x1, y1, x2, y2;
int w = 1024;
int h = 768;
color backgroundColor = color(255, 255, 255);
NaiveVerifier verifier;
PVector init;


void setup() {
  background(0);
  size(w, h);
}

void draw() {
}

void mouseClicked() {

  if (!first) {
    background(backgroundColor);
    first = true;
    x0 = mouseX;
    y0 = mouseY;
    x1 = x0;
    y1 = y0;
    verifier = new NaiveVerifier(backgroundColor);
  }
  else {
    x2 = mouseX;
    y2 = mouseY;

    if (mouseButton == LEFT) {
      bressenham(x1, y1, x2, y2);
      x1 = x2;
      y1 = y2;
    }
    else {
      bressenham(x0, y0, x1, y1);
      stroke(random(1, 250), random(1, 250), random(1, 250));
      flood(new PVector(x2, y2), verifier);
      first = false;
    }
  }
}

void flood(PVector init, NaiveVerifier verifier) {
  ArrayList<PVector> points = new ArrayList<PVector>();
  points.add(init);
  while(!points.isEmpty()){
    PVector p = points.remove(points.size()-1);
    if(verifier.isInside(p)) point(p.x, p.y);
    PVector newP = new PVector(p.x, p.y+1);
    if(verifier.isInside(newP)) points.add(newP);
    newP = new PVector(p.x, p.y-1);
    if(verifier.isInside(newP)) points.add(newP);
    newP = new PVector(p.x+1, p.y);
    if(verifier.isInside(newP)) points.add(newP);
    newP = new PVector(p.x-1, p.y);
    if(verifier.isInside(newP)) points.add(newP);
  }
}


void bressenham(int x0, int y0, int x1, int y1) {

  if (x0 >= x1-1 && x0 <= x1+1) {
    int y = min(y0, y1);
    int x = x0;
    while (y<max (y0, y1)) {
      point(x, y);
      y += 1;
    }
  }
  else {
    int x, y;
    int endX, endY;
    boolean up;
    int dy;
    int dx;

    if (x0<x1) {
      x = x0;
      endX = x1;
      endY = y1;
      y = y0;
      dy = y1-y0;
      dx = x1-x0;
    }
    else {
      x = x1;
      endX = x0;
      endY = y0;
      y = y1;
      dy = y0-y1;
      dx = x0-x1;
    }
    up = endY < y;
    // f(x,y) = m*x + b - y = 0
    if (abs(dy/dx)<1) {
      int d = 2*dy + ((up)?dx:-1*dx);
      while ( x <= endX ) {
        point(x, y);
        x += 1;
        if (up) {
          y += ((d<0)?-1:0);
          d += 2*dy + ((d<0)?2*dx:0);
        }
        else {
          y += ((d>0)?1:0);
          d += 2*dy + ((d>0)?-2*dx:0);
        }
      }
      while (y < endY) {
        if (up) point(x, y++);
        else point(x, y--);
      }
    }
    else {
      int d = dy + ((up)?2*dx:-2*dx);
      if (up) {
        while (x <= endX && endY < y) {
          point(x, y);

          y += -1;
          x += (d>0)?1:0;
          d += 2*dx + ((d>0)?2*dy:0);
        }
      }
      else {
        while ( y <= endY ) {
          point(x, y);
          y += 1;
          x += (d<0)?1:0;
          d += -2*dx + ((d<0)?2*dy:0);
        }
      }
    }
  }
}




public class NaiveVerifier{
  
  color target;
  
  public NaiveVerifier(color back){
    target=back;
  }
  
  public boolean isInside(PVector point){
    int x = (int)point.x;
    int y = (int)point.y;
    return get(x,y) == (target);
  }
    
}


